package com.example.basic.web.service.terminal.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.basic.base.impl.BaseEntityServiceImpl;
import com.example.basic.exception.ServiceException;
import com.example.basic.utils.IdUtils;
import com.example.basic.utils.StringUtils;
import com.example.basic.web.enums.InstructStatusEnum;
import com.example.basic.web.mapper.terminal.TerminalRecordMapper;
import com.example.basic.web.model.binding.BindingInfo;
import com.example.basic.web.model.device.Device;
import com.example.basic.web.model.terminal.TerminalRecord;
import com.example.basic.web.response.TaskRemainsResponse;
import com.example.basic.web.service.binding.BindingInfoService;
import com.example.basic.web.service.common.CommonService;
import com.example.basic.web.service.device.DeviceService;
import com.example.basic.web.service.terminal.TerminalRecordService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

import java.util.List;
import java.util.Map;

import static com.example.basic.utils.CheckUtil.notNull;


@Service
public class TerminalRecordServiceImpl extends BaseEntityServiceImpl<TerminalRecordMapper, TerminalRecord> implements TerminalRecordService {

    @Resource
    private TerminalRecordMapper terminalRecordMapper;

    @Resource
    private CommonService commonService;

    @Resource
    private BindingInfoService bindingInfoService;

    @Resource
    private DeviceService deviceService;


    /**
     * 作业记录列表
     *
     * @param queryPage     分页
     * @param pharmCode     仓库编码
     * @param zoneCode      分区编码
     * @param depotCode     库位编码
     * @param beginTime     开始时间
     * @param endTime       结束时间
     * @param deviceName    设备名称
     * @param type 1-队列，2-记录
     * @return
     */
    @Override
    public IPage<TerminalRecord> queryList(Page<TerminalRecord> queryPage, String pharmCode, String zoneCode, String depotCode, String beginTime, String endTime, String deviceName, String type) {
        return terminalRecordMapper.queryList(queryPage,pharmCode,zoneCode,depotCode,beginTime,endTime,deviceName,type);
    }

    /**
     * 取消指令
     *
     * @param id         唯一id
     * @param deviceCode
     * @return
     */
    @Override
    public Boolean cancel(String id, String deviceCode) {
        notNull(id,"唯一id不能为空");

        //获取指令详情
        TerminalRecord terminalRecord = this.selectById(id);

        if(terminalRecord == null){
            throw new ServiceException("未获取到需要取消的作业指令");
        }

        if(!terminalRecord.getStatus().equals(InstructStatusEnum.IN_PROGRESS.getType())){
            throw new ServiceException("不是正在执行中的任务,不允许取消");
        }

        //更新遗体绑定信息
        BindingInfo bindingInfo = bindingInfoService.detail(terminalRecord.getRemainsCode());

        Device device = new Device();
        //设备编码不为空, 原设备被占用,起点位置更新到新点位
        if(StringUtils.emptyParams(deviceCode)){
            //获取上一任务终点设备信息
            device = deviceService.findByPoint(terminalRecord.getInstructStart());
            bindingInfo.setDeviceCode(device.getDeviceCode());
        }else {
            //新点位
            device = deviceService.detail(deviceCode);
            bindingInfo.setDeviceCode(deviceCode);
        }

        bindingInfo.setAgvCode(null);
        bindingInfoService.modify(bindingInfo);

        //取消任务,更新任务起点
        //更新当前任务为未执行
        terminalRecord.setStatus(InstructStatusEnum.WAIT.getType());
        terminalRecord.setInstructStart(device.getDevicePoint());
        this.mapper.updateById(terminalRecord);
        return true;
    }

    /**
     * 删除指令
     * @param id 唯一id
     * @return
     */
    @Override
    public Boolean delete(String id) {
        notNull(id,"唯一id不能为空");

        //获取指令详情
        TerminalRecord terminalRecord = this.selectById(id);

        if(terminalRecord == null){
            throw new ServiceException("未获取到需要删除的作业指令");
        }

        terminalRecord.setStatus(InstructStatusEnum.DELETE.getType());
        terminalRecord.setFinishTime(commonService.getDataBaseTime());
        preUpdate(terminalRecord);

        if(this.updateById(terminalRecord) > 0){
            return true;
        }
        throw new ServiceException("删除失败");
    }

    /**
     * 重发指令
     * @param id 唯一id
     * @return
     */
    @Override
    public TerminalRecord repeat(String id) {
        notNull(id,"唯一id不能为空");

        //获取指令详情
        TerminalRecord terminalRecord = this.selectById(id);

        if(terminalRecord == null){
            throw new ServiceException("未获取到需要删除的作业指令");
        }

        terminalRecord.setStatus(InstructStatusEnum.REPEAT.getType());
        preUpdate(terminalRecord);

        //更新原指令为已重发
        this.updateById(terminalRecord);

        //添加新指令
        TerminalRecord newInstruct = new TerminalRecord();
        BeanUtils.copyProperties(terminalRecord,newInstruct);
        newInstruct.setId(IdUtils.fastUUID());
        newInstruct.setInstructTime(commonService.getDataBaseTime());
        newInstruct.setStatus(InstructStatusEnum.IN_PROGRESS.getType());

        preCreate(newInstruct);
        this.insert(newInstruct);

        return newInstruct;
    }

    /**
     * 删除单据作业职业
     * @param documentNo 单据号
     */
    @Override
    public void deleteByDocument(String documentNo) {
        notNull(documentNo,"单据号不能为空");

        LambdaQueryWrapper<TerminalRecord> lqw = new LambdaQueryWrapper<>();
        lqw.eq(TerminalRecord::getDocumentNo,documentNo);
        this.mapper.delete(lqw);
    }

    @Override
    public void batchAdd(List<TerminalRecord> terminalRecordList) {

        terminalRecordList.forEach(terminalRecord -> {
            terminalRecord.setId(IdUtils.fastUUID());
            preCreate(terminalRecord);
        });

        saveBatch(terminalRecordList);
    }

    /**
     * 根据单据号获取需要执行的下一任务
     * @param documentNo 单据号
     * @return
     */
    @Override
    public TerminalRecord queryNextStruct(String documentNo) {
        notNull(documentNo,"单据号不能为空");

        LambdaQueryWrapper<TerminalRecord> lqw = new LambdaQueryWrapper<>();
        lqw.eq(TerminalRecord::getDocumentNo,documentNo);
        lqw.eq(TerminalRecord::getStatus,"0");
        lqw.orderByAsc(TerminalRecord::getSortNo);
        lqw.last("limit 1");

        return this.mapper.selectOne(lqw);
    }

    /**
     * 更新指令
     * @param terminalRecord
     * @return
     */
    @Override
    public TerminalRecord update(TerminalRecord terminalRecord) {
        notNull(terminalRecord.getId(),"唯一id不能为空");

        preUpdate(terminalRecord);

        this.updateById(terminalRecord);

        return terminalRecord;
    }

    /**
     * 获取下一任务节点  单据状态不为空
     * @param documentNo 单据号
     * @return
     */
    @Override
    public TerminalRecord queryNextNode(String documentNo) {
        notNull(documentNo,"单据号不能为空");

        LambdaQueryWrapper<TerminalRecord> lqw = new LambdaQueryWrapper<>();
        lqw.eq(TerminalRecord::getDocumentNo,documentNo);
        lqw.eq(TerminalRecord::getStatus,"0");
        lqw.isNotNull(TerminalRecord::getDocumentStatus);
        lqw.orderByAsc(TerminalRecord::getSortNo);
        lqw.last("limit 1");

        return this.mapper.selectOne(lqw);

    }

    /**
     * 出入库作业执行情况
     * @return
     */
    @Override
    public List<Map> homeInstructCount() {
        return this.mapper.homeInstructCount();
    }

    /**
     * 查询阻塞任务
     * @param deviceAddress 设备地址
     * @return
     */
    @Override
    public TerminalRecord queryBlockTask(String deviceAddress) {
        LambdaQueryWrapper<TerminalRecord> lqw = new LambdaQueryWrapper<>();
        lqw.eq(TerminalRecord::getInstructEnd,deviceAddress);
        lqw.eq(TerminalRecord::getStatus,InstructStatusEnum.BLOCK.getType());
        lqw.orderByAsc(TerminalRecord::getSortNo);
        lqw.last("limit 1");

        return this.mapper.selectOne(lqw);
    }

    /**
     * 查询等待任务
     * @param documentNo 单据号
     * @return
     */
    @Override
    public List<TerminalRecord> queryWaitTask(String documentNo) {

        LambdaQueryWrapper<TerminalRecord> lqw = new LambdaQueryWrapper<>();
        lqw.eq(TerminalRecord::getDocumentNo,documentNo);
        lqw.eq(TerminalRecord::getStatus,InstructStatusEnum.WAIT.getType());
        lqw.orderByAsc(TerminalRecord::getSortNo);
        lqw.last("limit 1");

        return this.mapper.selectList(lqw);
    }

    /**
     * 查询进行中的任务
     * @param documentNo 单据号
     * @return
     */
    @Override
    public TerminalRecord queryInProgressTask(String documentNo) {
        LambdaQueryWrapper<TerminalRecord> lqw = new LambdaQueryWrapper<>();
        lqw.eq(TerminalRecord::getDocumentNo,documentNo);
        lqw.eq(TerminalRecord::getStatus,InstructStatusEnum.IN_PROGRESS.getType());
        return this.mapper.selectOne(lqw);
    }

    /**
     * 批量更新
     * @param terminalRecordList
     */
    @Override
    public void batchUpdate(List<TerminalRecord> terminalRecordList) {
        updateBatchById(terminalRecordList);
    }

    /**
     * 根据任务示例id获取调度任务
     * @param taskRecordId
     * @return
     */
    @Override
    public TerminalRecord queryByTaskRecordId(String taskRecordId) {
        LambdaQueryWrapper<TerminalRecord> lqw = new LambdaQueryWrapper<>();
        lqw.eq(TerminalRecord::getTaskRecordId,taskRecordId);
        return this.mapper.selectOne(lqw);
    }

    /**
     * 强制完成
     *
     * @param id
     * @param deviceCode
     * @return
     */
    @Override
    public Boolean forceFinish(String id, String deviceCode) {
        LambdaQueryWrapper<TerminalRecord> lqw = new LambdaQueryWrapper<>();
        lqw.eq(TerminalRecord::getTaskRecordId,id);
        TerminalRecord terminalRecord = this.mapper.selectOne(lqw);

        if(terminalRecord == null){
            throw new ServiceException("未获取到需要完成的任务信息");
        }

        if(!terminalRecord.getStatus().equals(InstructStatusEnum.IN_PROGRESS.getType())){
            throw new ServiceException("不是正在执行中的任务,不允许直接完成");
        }

        //更新遗体绑定信息
        BindingInfo bindingInfo = bindingInfoService.detail(terminalRecord.getRemainsCode());

        Device device = new Device();
        //设备编码不为空, 原设备被占用,终点位置更新到新点位
        if(StringUtils.emptyParams(deviceCode)){
            device = deviceService.detail(bindingInfo.getDeviceCode());
        }else {
            //新点位
            device = deviceService.detail(deviceCode);
            bindingInfo.setDeviceCode(deviceCode);
        }

        bindingInfo.setAgvCode(null);
        bindingInfoService.modify(bindingInfo);

        //更新任务状态为完成
        //更新任务终点点位
        terminalRecord.setInstructEnd(device.getDevicePoint());
        terminalRecord.setStatus(InstructStatusEnum.FINISH.getType());
        this.updateById(terminalRecord);

        return true;
    }

    /**
     * 获取最新一条完成的任务
     * @param documentNo
     * @return
     */
    @Override
    public TerminalRecord queryFinishRecord(String documentNo) {
        LambdaQueryWrapper<TerminalRecord> lqw = new LambdaQueryWrapper<>();
        lqw.eq(TerminalRecord::getDocumentNo,documentNo);
        lqw.eq(TerminalRecord::getStatus,InstructStatusEnum.FINISH.getType());
        lqw.orderByDesc(TerminalRecord::getSortNo);
        lqw.last("limit 1");

        return this.mapper.selectOne(lqw);
    }

    /**
     * 将所有未完成的任务,直接完成
     * @param documentNo
     * @return
     */
    @Override
    public Boolean finishAllRecord(String documentNo) {

        return this.mapper.finishAllRecord(documentNo);
    }

    /**
     * 获取最大任务序号
     * @param documentNo
     * @return
     */
    @Override
    public Integer findMaxSortNo(String documentNo) {
        return this.mapper.findMaxSortNo(documentNo);
    }

    /**
     * 遗体信息列表
     * @param searchParam
     * @param sex
     * @param cremation
     * @return
     */
    @Override
    public IPage<TaskRemainsResponse> remainsTaskList(Page<TaskRemainsResponse> queryPage, String searchParam, String sex, String cremation) {
        return this.mapper.remainsTaskList(queryPage,searchParam,sex,cremation);
    }

}
